require({
  baseUrl: ""
}, ["treehugger/tree",
"treehugger/traverse",
"treehugger/js/parse",
"scriptbuilder",
"visitor",
"tree_ext",
"json2",
"jquery"
], function(tree, traverse, parsejs, scriptbuilder, visitor) {

  function output(text) {
    $('#output').val(text);
  }

  function update() {
    var source, ast;

    // Clear console
    if( typeof(console.clear) == 'function' ) console.clear();

    // Test input
    source = $("#input").val();
    
    // Parse the AST tree using uglify
    ast = parsejs.parse(source);
    traverse.addParentPointers(ast);

    // Process the batch block
    processBatch(ast[0]);
  }

  function processBatch(ast) {
    var identifier, service, serviceName,
        generatedCode, outString, input;

    identifier = ast[0];
    service = ast[1];
    block = ast[2];

    identifier.traverseTopDown(
      'LetDecl(name),', function(b) {
        identifier = b.name.value;
      }
    );
    if( !identifier ) 
      throw "illegal batch statement";

    if( service.cons == "ERROR" ) {
      throw "illegal batch statement";
    }
    serviceName = service[0].value;

    // Input for the batch script
    input = {};

    // Transform ForEeach nodes
    block[0].traverseTopDown('Call(_,_)', function() {
      var node = this;
      
      if( node[0].cons == 'PropAccess' ) {
        node[0].traverseTopDown('PropAccess(subject,"forEach")', function(b) {
          node.cons = 'ForEach';
        });
      }
    });
    
    $('#ast').val(block[0].toPrettyString());
    
    // Generate code
    var v = new visitor.Visitor(identifier);
    v.reset();
    v.dispatchVisit(block[0]); 

    // Start of batch closure
    outString  = '(function($service$){\n';
    outString += 'var $input$ = '+JSON.stringify(input)+';\n';
    // Body of batch closure
    outString += '\n/* Init code */\n';
    outString += v.getInit();
    outString += '\n/* Remote code */\n';
    outString += 'var $script$ = \'' + v.getRemote() + '\';\n';
    outString += 'var $result$ = $service$.execute($script$, $input$);\n';
    outString += '\n/* Local code */\n';
    outString += v.getLocal();
    // End of batch closure
    outString += '\n})('+serviceName+');';

    $('#output').val(outString);
  }

  require.ready(function() {
    $ii = false;
    $(document).ready(function() {
      $('#input').keyup(function(e) {
        if( e.keyCode < 35 || e.keyCode > 40 ) {
          clearTimeout($ii);
          $ii = setTimeout(update, 500);
        }
      });  
      update();
    });
  });
});
